#ifndef __DATATYPES_HPP__
#define __DATATYPES_HPP__


#include <set>

/* *********************************************************************** */
/* *********************************************************************** */
/* *********************************************************************** */
//                                Enums
/* *********************************************************************** */
/* *********************************************************************** */
/* *********************************************************************** */

// TODO Do we need multiple levels of Verbose anymore? Or just 'on'/'off'?
// NOTE remember to update each MinVerboseXXX function if any changes are made to this enum
// Specifies how much output each testXXX function produces.
enum class VerboseOptions
{
   None = 0,       // No output other than success, complete, and status reports like # of items updated
   Low,            // Small status reports from major functions
   High,           // Larger reports tracing program flow
   Debug           // All messages, for debugging
};

// The following functions test if VerboseOptions is the specified level or higher.
// Used for quick checks to see if log messages should be generated

// Low, High, or Debug
inline bool MinVerboseLow(VerboseOptions verboseOptions) {
  if (verboseOptions != VerboseOptions::None) {
    return true;
  }
  return false;
}
// High or Debug
inline bool MinVerboseHigh(VerboseOptions verboseOptions) {
  if (verboseOptions != VerboseOptions::None && verboseOptions != VerboseOptions::Low) {
    return true;
  }
  return false;
}
// Debug
inline bool MinVerboseDebug(VerboseOptions verboseOptions) {
  if (verboseOptions == VerboseOptions::Debug) {
    return true;
  }
  return false;
}



// What method is used to Trim strings?
enum class TrimOptions
{
   None = 0,         // Trim nothing, leave string intact
   Whitespace,       // Only trims left and right whitespace
   ExtractNumber,    // Trims left/right and then removes anything not a number on left/right  " q4.25%  " -> "4.25"
                     // '-' is preserved on left but not '+',    "xxx.4" -> ".4"
                     // Only modifies the left/right, middle is preserved  "  4.25  4.25  " -> "4.25  4.25"
   ForSQL	  
};


// TODO There are three types of floats.
//      45.67   normal
//     +45.67   signed (can be negative)
//     +45.67%  signed percent (can be negative)
// Should we have three seperate types to help downstream code know how to format it? This would store formatting
// information in one place. 
// Consider having two values. Base type and format type. Format type describes decorations or precision.


enum class FieldNameType
{
    // All fields initially are Unknown and are treated as strings until their type is specified.  
    // Treat FieldNameType::Unknown as a string for all display purposes.
    // FieldNameType::String is a known string, Unknown may be some other type but we display as a string
    Unknown = 0,
    String, 
    Double,
    Int64, 
    Date, DateTime,
    
    // TODO Some fields contain multiple values, like a year high and low range, seperated by hyphens. 
    // Use FieldNameType::MultipleValues and treat them as strings for now. This will identify them as ranges.
    // A few fields have three values. Break these out into variables once we've looked at more data and determine
    // what these fields contain.
    MultipleValues,
    // TODO Not sure what to call this, any number with a K M or B, like 35.2M or 4.2B. Treat them as strings for now.
    LargeNumber
    
};


// All known FieldName's that are returned by YQL queries.
enum class FieldName 
{
   Unknown = 0, 
   // finance.yahoo.historical
   Open, High, Low, Close, Adj_Close, Volume, Record_Date,
   // finance.yahoo.quotes
      // dupes: Volume, Open
   Ask, AverageDailyVolume, Bid, AskRealtime, BidRealtime, BookValue, Change_PercentChange, Change, 
   Commission, Currency, ChangeRealtime, AfterHoursChangeRealtime, DividendShare, LastTradeDate, 
   TradeDate, EarningsShare, ErrorIndicationreturnedforsymbolchangedinvalid, EPSEstimateCurrentYear, 
   EPSEstimateNextYear, EPSEstimateNextQuarter, DaysLow, DaysHigh, YearLow, YearHigh, HoldingsGainPercent,
   AnnualizedGain, HoldingsGain, HoldingsGainPercentRealtime, HoldingsGainRealtime, MoreInfo, 
   OrderBookRealtime, MarketCapitalization, MarketCapRealtime, EBITDA, ChangeFromYearLow, 
   PercentChangeFromYearLow, LastTradeRealtimeWithTime, ChangePercentRealtime, ChangeFromYearHigh, 
   PercebtChangeFromYearHigh, LastTradeWithTime, LastTradePriceOnly, HighLimit, LowLimit, DaysRange, 
   DaysRangeRealtime, FiftydayMovingAverage, TwoHundreddayMovingAverage, ChangeFromTwoHundreddayMovingAverage, 
   PercentChangeFromTwoHundreddayMovingAverage, ChangeFromFiftydayMovingAverage, 
   PercentChangeFromFiftydayMovingAverage, Name, Notes, PreviousClose, PricePaid, ChangeinPercent,
   PriceSales, PriceBook, ExDividendDate, PERatio, DividendPayDate, PERatioRealtime, PEGRatio, 
   PriceEPSEstimateCurrentYear, PriceEPSEstimateNextYear, Symbol, SharesOwned, ShortRatio, LastTradeTime, 
   TickerTrend, OneyrTargetPrice, HoldingsValue, HoldingsValueRealtime, YearRange, DaysValueChange, 
   DaysValueChangeRealtime, StockExchange, DividendYield, PercentChange
};





/* *********************************************************************** */
/* *********************************************************************** */
/* *********************************************************************** */
//                                TYPEDEFS
/* *********************************************************************** */
/* *********************************************************************** */
/* *********************************************************************** */

// Prototypes for typedefs
class FieldValuePair;

typedef std::map<FieldName, FieldValuePair> 	MapFieldNameToFieldValue;
typedef std::pair<FieldName, FieldValuePair> 	MapFieldNameToFieldValuePair;
typedef std::vector<FieldName> 			VectorFieldName;
typedef std::vector<FieldNameType>		VectorFieldNameType;
typedef std::set<std::string>                   SetString;

typedef std::vector<std::string>		VectorString;

#endif